package fr.univlille1.ftp;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class FTPTransferer extends Thread{

	private int port;
	private String message;
	private FTPCommands command;
	private File processingFile;
	private ServerSocket ss;
	private InetAddress address;
	private int offset;
	private PrintWriter commandStream;

	public FTPTransferer(char mode, int port, File currentDir, String message, FTPCommands command, InetAddress address, int offset, PrintWriter commandStream){
		this.port = port;
		this.message = message;
		this.command = command;
		this.processingFile = currentDir;
		this.address = address;
		this.ss = null;
		this.offset = offset;
		this.commandStream = commandStream;
	}

	public FTPTransferer(char mode, ServerSocket ss, File currentDir, String message, FTPCommands command, int offset, PrintWriter commandStream){
		this.port = -1;
		this.message = message;
		this.command = command;
		this.processingFile = currentDir;
		this.ss = ss;
		this.offset = offset;
		this.commandStream = commandStream;
	}

	public void run(){
		if(ss != null){
			this.passiveRun();
		}else{
			this.activeRun();
		}
		this.commandStream.write("220 Transfert done\r\n");
		this.commandStream.flush();
		return;
	}

	private void passiveRun(){
		try{
			Socket s = ss.accept();
			switch(this.command){
			case LIST:
				this.processList(new PrintWriter(s.getOutputStream()));
				break;
			case RETR:
				this.processRetr(s.getOutputStream());
				break;
			case STOR:
				this.processStor(s.getInputStream());
				break;
			default:
				break;
			}
			s.close();
		}catch(IOException e){
			e.printStackTrace();
		}
	}

	private void activeRun(){
		try{
			System.out.println("Attempting connection on address "+this.address.toString()+" with port "+this.port);
			Socket s = new Socket();
			s.connect(new InetSocketAddress(this.address, this.port));
			switch(this.command){
			case LIST:
				this.processList(new PrintWriter(s.getOutputStream()));
				break;
			case RETR:
				this.processRetr(s.getOutputStream());
				break;
			default:
				break;
			}
			s.close();
		} catch(IOException e){
			e.printStackTrace();
		}
	}

	private void processList(PrintWriter output){
		File workingDir = null;
		if(this.message.equals("LIST")){
			workingDir = this.processingFile;
		}else{
			workingDir = new File(this.message.substring(5));
		}
		try {
			String buffer = "";
			Process p = Runtime.getRuntime().exec("ls -n --time-style=\"+%b%e  %Y\" "+workingDir.getAbsolutePath());
			BufferedReader is = new BufferedReader(new InputStreamReader(p.getInputStream()));
			buffer = is.readLine();
			while(buffer != null){
				buffer = is.readLine();
				output.write(buffer+"\r\n");
				output.flush();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void processRetr(OutputStream output){
		try{
			RandomAccessFile raf = new RandomAccessFile(this.processingFile, "r");
			raf.seek(this.offset);
			byte[] buffer = new byte[1024];
			int nbBytes;
			do{
				nbBytes = raf.read(buffer);
				if(nbBytes != -1) output.write(buffer, 0, nbBytes);
			}while(nbBytes != -1);
			raf.close();
			output.flush();
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	
	private void processStor(InputStream input) {
		try{
			FileOutputStream fos = new FileOutputStream(this.processingFile, true);
			byte[] buffer = new byte[1024];
			int nbBytes;
			do{
				nbBytes = input.read(buffer);
				if(nbBytes != -1) fos.write(buffer, 0, nbBytes);
			}while(nbBytes != -1);
			fos.close();
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	
}

